#include "Epik_Model.h"
#include "Epik_Vertex.h"
#include "Epik_Movement.h"
#include <sys/types.h>
#include <pspiofilemgr.h>
#include <pspgu.h>
#include <pspgum.h>
#include <psptypes.h>
#include <pspkerneltypes.h>
#include <pspthreadman.h>
#include <psprtc.h>
#include <stdio.h>
#include <string.h>
#include <cstdlib>
#include <pspdebug.h>
#include <math.h>

// Opens and parses the model file
Epik_Model::Epik_Model(const char *filename)
:moving_(false),vCnt_(0),pCnt_(0),moves_(0)
{
	strcpy(name_, filename);
	scale_.x=1;
	scale_.y=1;
	scale_.z=1;

	SceUID file;
	file = sceIoOpen(name_, PSP_O_RDONLY, 0777);
	if (file<0)
		pspDebugScreenPrintf("Error opening '%s' (0x%08X)\n", name_, file);
	else
	{
		pspDebugScreenPrintf("  Succesfully opened '%s'.\n", name_);
		// Get File Size
		SceOff fSize =	sceIoLseek(file, 0, 2);	// 2 = SEEK_END
	  /*SceOff fCurr =*/sceIoLseek(file, 0, 0);	// 0 = SEEK_SET

		char *fContents = new char[fSize];
		char *str = fContents;
		sceIoRead(file, (void *)fContents, fSize);

		char keyword[5];
		int n;

		while( sscanf(str, "%4s%n", keyword, &n)==1 )
		{
			str += n;
			n = 0;

			if/* */( strcmp(keyword,"v" )==0 )
				str += keyV(str);
			else if( strcmp(keyword,"vc")==0 )
				str += keyVC(str);
			else if( strcmp(keyword,"n" )==0 )
				str += keyN(str);
			else if( strcmp(keyword,"ms")==0 )
				str += keyMS(str);
			else if( strcmp(keyword,"pc")==0 )
				str += keyPC(str);
			else if( strcmp(keyword,"pf")==0 )
				str += keyPF(str);
			else if( strcmp(keyword,"pp")==0 )
				str += keyPP(str);
			else if( strcmp(keyword,"pr")==0 )
				str += keyPR(str);
			else if( strcmp(keyword,"mv")==0 )
				str += keyMV(str);
			else if( strcmp(keyword,"mvc")==0 )
				str += keyMVC(str);
		}

		pspDebugScreenPrintf("Succesfully loaded '%s' to memory.\n", name_);
		sceIoClose(file);
	}
}


// Destructor; liberates part arrays
Epik_Model::~Epik_Model()
{
	delete [] partPos_;
	delete [] partRot_;
	delete [] parts_;
}


// Draws the model
void Epik_Model::Render()
{
//	pspDebugScreenPrintf("Model::Render('%s')\n", name_);
	sceGumPushMatrix();
	sceGumScale(&scale_);

	if( moving_ )
	{
		u64 time;
		sceRtcGetCurrentTick(&time);

		if (time >= moveSpec_->moveEnd_)
			moving_ = false;
		else
		{
			float percent = (float)(time-moveSpec_->moveStart_)/(float)(moveSpec_->moveEnd_-moveSpec_->moveStart_);
			ScePspFVector3 curr = {percent * (moves_[moveSpec_->moveID_].rot_.x - moveSpec_->start_.x),
								   percent * (moves_[moveSpec_->moveID_].rot_.y - moveSpec_->start_.y),
								   percent * (moves_[moveSpec_->moveID_].rot_.z - moveSpec_->start_.z)};
			sceGumRotateXYZ(&curr);
		}
	}

	sceGumDrawArray(GU_TRIANGLES, GU_TRANSFORM_3D|GU_VERTEX_32BITF|GU_COLOR_8888, vCnt_, 0, part_);
	for(int i=0; i<pCnt_; i++)
	{
		ScePspFVector3 reversePos = {partPos_[i].x*(-1.0f), partPos_[i].y*(-1.0f), partPos_[i].z*(-1.0f)};
		ScePspFVector3 reverseRot = {partRot_[i].x*(-1.0f), partRot_[i].y*(-1.0f), partRot_[i].z*(-1.0f)};

		sceGumTranslate(&partPos_[i]);
		sceGumRotateXYZ(&partRot_[i]);

		parts_[i]->Render();

		sceGumRotateZYX(&reverseRot);
		sceGumTranslate(&reversePos);
	}

	sceGumPopMatrix();
}


// Make the model move to selected index
void Epik_Model::SetMove(const int moveIndex)
{
	if (moves_!=0)
	{
		u64 time;
		float percent;

		sceRtcGetCurrentTick(&time);
		if( moving_ )
		{
			percent = (float)(time - moveSpec_->moveStart_)/(float)(moveSpec_->moveEnd_ - moveSpec_->moveStart_);

			moveSpec_->start_.x = (percent * (moves_[moveSpec_->moveID_].rot_.x - moveSpec_->start_.x));
			moveSpec_->start_.y = (percent * (moves_[moveSpec_->moveID_].rot_.y - moveSpec_->start_.y));
			moveSpec_->start_.z = (percent * (moves_[moveSpec_->moveID_].rot_.z - moveSpec_->start_.z));
		}

		moveSpec_->moveID_ = moveIndex;
		sceRtcGetCurrentTick(&moveSpec_->moveStart_);
		moveSpec_->moveEnd_ = (moveSpec_->moveStart_ + moves_[moveIndex].time_);
		moving_ = true;
	}
	for( int i=0; i<pCnt_; i++ )
		parts_[i]->SetMove(moveIndex);
}

// Defines a variation in scale over time (MS = Move Scale)
int Epik_Model::keyMS(const char *str)
{
	int ret;

	sscanf(str, "%f%f%f%n", &scale_.x, &scale_.y, &scale_.z, &ret);

	return ret;
}


// Defines the quantity of movements (MVC = MoVe Count)
int Epik_Model::keyMVC(const char *str)
{
	int moveCnt, ret;

	sscanf(str, "%d%n", &moveCnt, &ret);
	if (moveCnt > 0)
		moves_ = new Epik_Movement[moveCnt];

	return ret;
}


// Defines a movement step (MV = MoVe)
//   MV  <index>  <duration>   <x_rot>  <y_rot>  <z_rot>
int Epik_Model::keyMV(const char *str)
{
	int moveIndex, ret;
	unsigned long int time;
	float x, y, z;

	sscanf(str, "%d%lu%f%f%f%n", &moveIndex, &time, &x, &y, &z, &ret);
	pspDebugScreenPrintf("Rotating mod %d to (%f,%f,%f) in %lu microseconds.\n", moveIndex, x, y, z, time);
	moves_[moveIndex-1].time_ = time;
	moves_[moveIndex-1].rot_.x = x*(M_PI/180.0f);
	moves_[moveIndex-1].rot_.y = y*(M_PI/180.0f);
	moves_[moveIndex-1].rot_.z = z*(M_PI/180.0f);

	return ret;
}


// Defines the model's name
int Epik_Model::keyN(const char *str)
{
	int ret;

	sscanf(str, "%s%n", name_, &ret);
	pspDebugScreenPrintf("Loading '%s.em'\n", name_);

	return ret;
}


// Defines how many children are attached (PC = Part Count)
int Epik_Model::keyPC(const char *str)
{
	int i, ret;

	sscanf(str, "%d%n", &i, &ret);
	parts_ = new Epik_Model*[i];
	partPos_ = new ScePspFVector3[i];
	partRot_ = new ScePspFVector3[i];
	pCnt_=i;

	return ret;
}


// Defines a child part to be rendered (PF = Part File)
//   The extension must not be present.
int Epik_Model::keyPF(const char *str)
{
	char fn[32] = {0};
	char file[128] = {0};
	int i, ret;

	sscanf(str, "%d%s%n", &i, fn, &ret);
//	strcpy(file,"Graphics/");
	strcat(file,fn);
	strcat(file,".em");
	parts_[i-1] = new Epik_Model(file);
	pspDebugScreenPrintf("Done setting up %s.em\n", fn);

	return ret;
}


// Defines the part's position from it's parent part (PP = Part Position)
int Epik_Model::keyPP(const char *str)
{
	int i, ret;
	float x,y,z;

	sscanf(str, "%d%f%f%f%n", &i, &x, &y, &z, &ret);
	pspDebugScreenPrintf("Model %d is placed at (%f, %f, %f)\n", i, x, y, z);
	partPos_[i-1].x = x;
	partPos_[i-1].y = y;
	partPos_[i-1].z = z;

	return ret;
}


// Defines the part's default rotation (PR = Part Rotation)
int Epik_Model::keyPR(const char *str)
{
	int i,ret;
	float x,y,z;

	sscanf(str, "%d%f%f%f%n",&i, &x, &y, &z, &ret);
	partRot_[i-1].x = x*(M_PI/180.0f);
	partRot_[i-1].y = y*(M_PI/180.0f);
	partRot_[i-1].z = z*(M_PI/180.0f);
//	pspDebugScreenPrintf("Model is rotated at (%f, %f, %f)\n", rot_[i-1].x, rot_[i-1].y, rot_[i-1].z);

	return ret;
}


// Defines a single vertex (V = Vertex)
int Epik_Model::keyV(const char *str)
{
	int ret;

	sscanf(str, "%X%f%f%f%n", &part_[vCnt_].color_, &part_[vCnt_].x_, &part_[vCnt_].y_, &part_[vCnt_].z_, &ret);
	vCnt_++;

	return ret;
}


// Defines the number ov vertices (VC = Vertex Count)
int Epik_Model::keyVC(const char *str)
{
	int ret, partCnt;

	sscanf(str, "%d%n", &partCnt, &ret);
	part_ = new Vertex[partCnt];

	return ret;
}
